【1dayソロハッカソン】MUIとTypeScriptの勉強しつつ卓球ラケット診断アプリ作ってみた!
こんにちは、戸田です。
暇な日があったので 1day ソロハッカソンやってみました!(勝手に名前つけました)
今回は卓球ラケット診断アプリを作りました。
MUI と TypeScript の勉強も含めているのでさっくりとした簡単なアプリです。
どんなアプリか
スタート画面から 2or3 択で自分のスタイルを選択していき、おすすめのラケットとラバーを教えてくれるアプリです。
選択画面 | 結果画面 |
---|---|
以下の URL から実際に試せます。
環境
- Vite (v5.3.4)
- React (v18.3.1)
- Material-UI (MUI) (v5.16.6)
- Emotion (v11.13.0)
- Styled Components (v6.1.12)
アイデア出し
最近卓球にハマったので卓球に関わるアプリがいいなぁと思っていました。
オフィスでの卓球の様子 ↓
ハッカソン前の金曜日に会社の人とラケットを買いに行き、ラケットとラバー選びにかなり迷いました。
そこから簡単にラケットのタイプを診断してくれるアプリにしようと決めました。
といっても 1 日しか時間がなく、勉強もしつつ作りたかったので既存のものになってしまいました 😭
この点については結構反省です...(ハッカソンというからには新しいものを作りたかった)
データ集め
卓球経験がなくあまりラケットとラバーについて詳しくないため検索しつつフローチャートを AI に組んでもらいました。
AI に頼りすぎてテニスと混ざってる部分があるかもです。(データはいつでも変えられるので一旦放置)
そしてこれを AI でいい感じに JSON にしてもらいました。
JSON の形式は設計に関わる重要ポイントだと思いますが、「React に合わせて JSON を作成して」とプロンプトを書いたら割といい感じになりました。自分でも中身を確認して React でこのデータを使ってフローチャート的な実装ができると思ったのでそのまま採用しました。
{
"nodes": [
{
"id": "A",
"text": "卓球ラケット選択",
"type": "start",
"nextId": "B"
},
{
"id": "B",
"text": "プレイスタイル?",
"type": "question",
"options": [
{
"text": "攻撃的",
"nextId": "C"
},
{
"text": "守備的",
"nextId": "D"
},
{
"text": "オールラウンド",
"nextId": "E"
}
]
},
{
"id": "C",
"text": "主な攻撃方法?",
"type": "question",
"options": [
{
"text": "スマッシュ/ドライブ",
"nextId": "F"
},
{
"text": "スピン",
"nextId": "G"
},
{
"text": "ボレー",
"nextId": "H"
}
]
},
{
"id": "D",
"text": "得意なショット?",
"type": "question",
"options": [
{
"text": "ロブ",
"nextId": "I"
},
{
"text": "スライス",
"nextId": "J"
},
{
"text": "カウンター",
"nextId": "K"
}
]
<!-- 長いのでここまで -->
}]
}
環境構築
今まで create-react-app でしか環境を作ったことがなかったので、初めて vite を使ってインストールしてみました。
npm create vite@latest
ライブラリ・フレームワークの種類はもちろん React で言語は TypeScript にしました。
でも、最近の React は別の React フレームワークを使ってプロジェクトを始めることをオススメしていそう。
MUI のインストールは公式サイトを参考にして以下のコマンドを実行しました。
npm install @mui/material @emotion/react @emotion/styled
npm install @mui/material @mui/styled-engine-sc styled-components
実装
色を決める
まず UI で使用する色をpalettemakerというサイトを使用して決めました。
型指定
次に型指定のためデータ集めの時に作成した JSON データの interface を作成しました。ここも JSON データを AI に送信してタイプ指定をしてというプロンプトでうまくやってくれました。
export type NodeType = "start" | "question" | "answer" | "result";
export interface Option {
text: string;
nextId: string;
}
export interface Node {
id: string;
text: string;
type: NodeType;
options?: Option[];
nextId?: string;
}
export interface FlowchartData {
nodes: Node[];
}
MUI を勉強しつつ作り上げる
MUI は独自のコンポーネントでスタイルを調整するので公式ドキュメントを見ながら欲しい UI になるものを探して実装していきました。普段から CSS は書いているので覚えは早かったです。
機能を実装
機能自体はかなりシンプルです。現在のノード ID(currentId)を持つものノードと option の数だけ選択ボタンを表示します。ボタンが押されたら option の nextId を参照して currentId 切り替えます。
アニメーションを追加
ただ切り替わるだけだと見た目が寂しかったのでアニメーションを追加しました。
今回は MUI のZoomを使用して中央から広がるように出現するアニメーションにしてみました。
困ったこと
Zoom コンポーネントを使用してもボタンで選択した時にアニメーションが発生しないことがありました。これは再レンダリングがされないことが原因だったので key に currentNode.id を追加して毎回レンダリングがされるようにしたところうまく動作しました。
<Zoom in={currentNode ? true : false} key={currentNode.id}>
テスト
テストのコードを書いたわけではありませんが、手動でバグの確認をしました。
完成!
既存のものだとしてもアニメーションがついていたり好きな UI にできるのでオリジナル感があります。次は何を作ろうかなぁ
最近の卓球活動について
クラスメソッドの日比谷オフィスには常に卓球台が置いてあるのでお昼ご飯を食べた後、退勤をした後に社内のメンバーで卓球をして遊んでいます。
最近ラケットを買って少し気分が上がっています。
ちなみに僕のラケットは以下の構成です。
いつでも対戦相手募集中です!